const std = @import("std");
pub const builtin = @import("builtin");
pub const is_test = @import("builtin").is_test;
pub const is_kernel = @hasDecl(@import("root"), "os");
pub const is_64_bit = @bitSizeOf(usize) == 64;
pub const native_endian = builtin.target.cpu.arch.endian();

pub const arch = struct {
    pub const qemu = @import("arch/qemu.zig");
    pub const intr = @import("arch/intr.zig");
    pub const vms = @import("arch/vms.zig");

    /// load/save reg, offset(base)
    /// Generates memory operation (load/store) for a register and offset.
    pub inline fn op(kind: enum { load, save }, reg: anytype, offset: usize, base: anytype) void {
        @setEvalBranchQuota(20000);
        const cmd = (if (kind == .load) "l" else "s") ++ (if (is_64_bit) "d" else "w");
        asm volatile (std.fmt.comptimePrint("{s} {t}, {d}({t})", .{ cmd, reg, offset, base }));
    }
};

// The os module can be used by mkfs, which doesn't require locking.
// Adding locks would make it incompatible with mkfs.
pub const Lock = struct {
    pub const Sleep = if (is_kernel) @import("Lock/Sleep.zig") else Void;
    pub const Spin = if (is_kernel) @import("Lock/Spin.zig") else Void;

    const Void = struct {
        pub fn init(_: []const u8) Void {
            return .{};
        }
    };

    // https://ziglang.org/download/0.14.0/release-notes.html#Synchronize-External-Operations
    var atomic: std.atomic.Value(u8) = .init(0);
    pub fn fence() void {
        _ = atomic.fetchAdd(0, .acq_rel);
    }
};

pub const fs = @import("fs.zig");
pub const mem = @import("mem.zig");
pub const net = @import("net.zig");
pub const proc = @import("proc.zig");
pub const trap = @import("trap.zig");
pub const syscall = @import("syscall.zig");
pub const debug = @import("debug.zig");
pub const driver = @import("driver.zig");
pub const lib = @import("lib.zig");
pub const fdt = @import("fdt.zig");

pub const heap = struct {
    // override std.heap.page_allocator
    pub const page_allocator = mem.PageAllocator.allocator;
};

pub const PGSIZE = mem.PGSIZE;
pub const STACK_PER_CPU = PGSIZE * 8;
pub const KSTACK = 8;
pub const USTACK = 8;

/// maximum number of processes
pub const NPROC = 64;
/// maximum number of CPUs
pub const NCPU = 8;
/// open files per process
pub const NOFILE = 16;
/// open files per system
pub const NFILE = 100;
/// maximum number of active i-nodes
pub const NINODE = 50;
/// maximum major device number
pub const NDEV = 10;
/// console device number
pub const CONSOLE = 1;
/// null device number
pub const NULL = 2;
/// max exec arguments
pub const MAXARG = 32;
